package net.sql;

import java.lang.reflect.Method;
import java.util.Map;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import net.dotool.StringTools;
import net.sql.config.SQLBean.IfBean;
import net.sql.bean.SqlFieldType;
import net.sql.bean.SqlParam;
import net.sql.config.SQLConfig;

/**
 * @author 李岩飞
 * @email eliyanfei@126.com
 * @date 2018年7月23日下午5:02:46
 */
public class SqlIf {
	private static ClassPool pool = ClassPool.getDefault();
	private SqlParam sqlParam;
	private Map<String, IfBean> ifMap;
	private Class<?> clazz = null;
	private Object object;

	public SqlIf(SqlParam sqlParam, Map<String, IfBean> ifMap) {
		this.sqlParam = sqlParam;
		this.ifMap = ifMap;
		CtClass cc = pool.makeClass("net.sql.SQLIF" + (SQLConfig.INDEX++));
		init(cc);
	}

	/**
	 * 判断数据是否为真
	 */
	public boolean test(String id) {
		try {
			Method method = clazz.getDeclaredMethod(id);
			Object result = method.invoke(object);
			return (boolean) result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 创建表达式函数
	 */
	private void initIfMethod(CtClass cc) {
		try {
			for (IfBean bean : ifMap.values()) {
				String methodName = bean.id;
				String body = "public boolean " + methodName + "() {return (" + bean.test + ");}";
				body = body.replaceAll("''", "\"\"");
				body = body.replaceAll(" and ", " && ");
				body = body.replaceAll(" or ", " || ");
				CtMethod m = CtMethod.make(body, cc);
				cc.addMethod(m);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 初始化参数
	 */
	private void init(CtClass cc) {
		for (String key : sqlParam.getParams().keySet()) {
			initMethod(cc, key, sqlParam.getParams().get(key));
		}
		initIfMethod(cc);
		try {
			clazz = cc.toClass();
			object = clazz.newInstance();
			for (String key : sqlParam.getParams().keySet()) {
				callMethod(key, sqlParam.getParams().get(key));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 调用set方法赋值
	 * 
	 * @param name
	 * @param value
	 */
	private void callMethod(String name, Object value) {
		try {
			if (value == null)
				return;
			SqlFieldType fieldType = new SqlFieldType(value.getClass().getSimpleName());
			String setMethodName = "set" + StringTools.capitalize(name);
			Method method = clazz.getDeclaredMethod(setMethodName, fieldType.baseClass);
			method.invoke(object, value);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 创建字段变量和set，get方法
	 */
	private void initMethod(CtClass cc, String fieldName, Object fieldValue) {
		try {
			// if (fieldValue == null)
			// return;
			// 获取给字段的基本类型名称和class
			SqlFieldType fieldType = new SqlFieldType(
					fieldValue == null ? String.class.getSimpleName() : fieldValue.getClass().getSimpleName());
			// 创建字段，这里选择基本类型
			String fd = "private " + fieldType.baseType + " " + fieldName + ";";
			CtField field = CtField.make(fd, cc);
			cc.addField(field);
			// 创建set，get方法
			String setMethodName = "set" + StringTools.capitalize(fieldName);
			String getMethodName = "get" + StringTools.capitalize(fieldName);
			StringBuilder sb = new StringBuilder();
			sb.append("public void ").append(setMethodName);
			sb.append("(").append(fieldType.baseType).append(" ").append(fieldName).append(")");
			sb.append("{ this.").append(fieldName).append("=$1;}");
			CtMethod m1 = CtMethod.make(sb.toString(), cc);
			cc.addMethod(m1);
			sb.setLength(0);
			sb.append("public ").append(fieldType.baseType).append(" ");
			sb.append(getMethodName).append("()");
			sb.append("{ return this.").append(fieldName).append(";}");
			CtMethod m2 = CtMethod.make(sb.toString(), cc);
			cc.addMethod(m2);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
